package service

import (
	"errors"
	"gorm.io/gorm"
	"shop-common/library/loggerV2"
	"shop-common/library/variables"
	"shop-common/utils/pagehelper"
	"shop-common/utils/queryWrapper"
	"shop-sys/model"
	"shop-sys/pkg/request"
	"shop-sys/pkg/vo"
	"shop-sys/repository"
)

type ISysRoleService interface {
	SaveRoleAndRoleMenu(request *request.SysRoleRequest, internalId uint) (roleId uint, err error)
	CheckRoleNameExist(roleName string) (bool, error)
	PageRole(request *pagehelper.SearchPageRequest) (*pagehelper.Record, error)
	FindRole(pair *queryWrapper.WherePair) (list []*vo.SysRolePageVO, err error)
	DeleteBatch(roleIds []uint) error
	UpdateRoleAndRoleMenu(request *request.SysRoleRequest, roleId uint) error
	FindById(roleId uint) (*model.SysRole, error)
	FindInRoleIds(isOnlineIds []uint) ([]uint, error)
}

type SysRoleService struct {
	db                    *gorm.DB
	sysRoleRepository     repository.ISysRoleRepository
	sysRoleMenuRepository repository.ISysRoleMenuRepository
	sysUserRoleRepository repository.ISysUserRoleRepository
}

func NewSysRoleService() ISysRoleService {
	return &SysRoleService{
		db:                    variables.GormDB(),
		sysRoleRepository:     repository.NewSysRoleRepository(),
		sysRoleMenuRepository: repository.NewSysRoleMenuRepository(),
		sysUserRoleRepository: repository.NewSysUserRoleRepository(),
	}
}

/**
 * 保存角色 与 角色菜单关系
 * @param userId
 * @param role
 */
func (s *SysRoleService) SaveRoleAndRoleMenu(request *request.SysRoleRequest, internalId uint) (roleId uint, err error) {
	role := &model.SysRole{
		RoleName:     request.RoleName,
		Remark:       request.Remark,
		CreateUserId: internalId,
	}

	err = s.db.Transaction(func(tx *gorm.DB) error {
		// 增加角色
		roleId, err := s.sysRoleRepository.Create(tx, role)
		if err != nil {
			loggerV2.Errorf("create sysRole failed: err %v, userId: %d, request: %+v", err, internalId, request)
			return err
		}

		//保存角色与菜单关系
		if len(request.MenuIds) > 0 {
			if err := s.sysRoleMenuRepository.CreateRoleAndRoleMenu(tx, roleId, request.MenuIds); err != nil {
				loggerV2.Errorf("create sysRole and sysRoleMenu association failed: err %v, roleId: %d, request: %+v", err, roleId, request)
				return err
			}
		}

		return nil
	})

	return role.RoleId, err
}

func (s *SysRoleService) CheckRoleNameExist(roleName string) (bool, error) {
	exist, err := s.sysRoleRepository.CheckUserExist(s.db, &queryWrapper.WherePair{Query: "role_name = ?", Args: []interface{}{roleName}})
	if err != nil {
		loggerV2.Errorf("by roleName checkUserExist failed: err %v, roleName %s", err, roleName)
		return exist, err
	}
	return exist, nil
}

/**
 * 获取角色分页列表
 * @param pagehelper.SysSearchPageRequest
 */
func (s *SysRoleService) PageRole(request *pagehelper.SearchPageRequest) (*pagehelper.Record, error) {
	paginator := pagehelper.New().
		SetOffset(request).
		IsPush(request.Keyword != "", queryWrapper.Like("role_name", request.Keyword)).
		SetFilter([]string{"role_id"}).Paginator()
	count, err := s.sysRoleRepository.Count(s.db, paginator.Params)
	if err != nil {
		loggerV2.Errorf("find sysRole to count failed: err %v, params %+v", err, paginator.Params)
		return paginator.Record, err
	}

	if count == 0 {
		return paginator.Record, nil
	}

	page, err := s.sysRoleRepository.FindPage(s.db, paginator.Params)
	if err != nil {
		loggerV2.Errorf("find sysRole to page: err: %v, params %+v", err, paginator.Params)
		return paginator.Record, err
	}

	paginator.Count(count).Record.List = page

	return paginator.Record, nil
}

func (s *SysRoleService) FindRole(pair *queryWrapper.WherePair) (list []*vo.SysRolePageVO, err error) {
	list, err = s.sysRoleRepository.FindRole(s.db, pair)
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		loggerV2.Errorf("findRole to pair filed: err %v, pair %+v", err, pair)
		return nil, err
	}
	return list, nil
}

/**
 * 根据id批量删除
 * @param roleIds
 */
func (s *SysRoleService) DeleteBatch(roleIds []uint) error {
	return s.db.Transaction(func(tx *gorm.DB) error {
		//删除角色
		err := s.sysRoleRepository.DeleteBatch(tx, roleIds)
		if err != nil {
			loggerV2.Errorf("batch delete by roleIds failed: err %v, roleIds: %d", err, roleIds)
			return err
		}

		//删除角色与菜单关联
		err = s.sysRoleMenuRepository.DeleteBatch(tx, "role_id = ?", roleIds)
		if err != nil {
			loggerV2.Errorf("batch delete by roleIds sysRole and roleMenu association failed: err %v, roleIds %d", err, roleIds)
			return err
		}

		//删除角色与用户关联
		err = s.sysUserRoleRepository.DeleteBatch(tx, roleIds)
		if err != nil {
			loggerV2.Errorf("batch delete by roleIds sysUserRole and sysRole association failed: err %v, roleIds %d", err, roleIds)
			return err
		}

		return nil
	})
}

/**
 * 更新角色 与 角色菜单关系
 * @param role
 */
func (s *SysRoleService) UpdateRoleAndRoleMenu(request *request.SysRoleRequest, roleId uint) error {
	return s.db.Transaction(func(tx *gorm.DB) error {
		// 更新角色
		columns := map[string]interface{}{
			"role_id":   roleId,
			"role_name": request.RoleName,
			"remark":    request.Remark,
		}
		if err := s.sysRoleRepository.Updates(tx, roleId, columns); err != nil {
			loggerV2.Errorf("updates by roleId columns failed: err %, roleId %d, columns %+v", err, roleId, columns)
			return err
		}

		//先删除角色与菜单关系
		if err := s.sysRoleMenuRepository.DeleteBatch(tx, "role_id = ?", []uint{roleId}); err != nil {
			loggerV2.Errorf("batch delete sysRoleMenu and sysRole association failed: err %v, roleId %d", err, roleId)
			return err
		}

		if len(request.MenuIds) > 0 {
			//保存角色与菜单关系
			if err := s.sysRoleMenuRepository.CreateRoleAndRoleMenu(tx, roleId, request.MenuIds); err != nil {
				loggerV2.Errorf("create sysRole and sysRoleMenu association failed: err %v, menuIds %s", err, request.MenuIds)
				return err
			}
		}

		return nil
	})
}

func (s *SysRoleService) FindById(roleId uint) (*model.SysRole, error) {
	sysRole, err := s.sysRoleRepository.FindById(s.db, roleId)
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		loggerV2.Errorf("find by roleId sysRole failed: err %, roleId %d", err, roleId)
		return nil, err
	}
	return sysRole, nil
}

func (s *SysRoleService) FindInRoleIds(isOnlineIds []uint) ([]uint, error) {
	roleIds, err := s.sysRoleRepository.FindByInRoleId(s.db, isOnlineIds)
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		loggerV2.Errorf("find by IN rid failed: err %v, isOnlineIds %d", err, isOnlineIds)
		return nil, err
	}

	return roleIds, nil
}
